﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Simpletron
{
  public class InstructionFactory
  {
    private static Dictionary<SimpletronOpCodes, Instruction> map;

    static InstructionFactory()
    {
      map = new Dictionary<SimpletronOpCodes, Instruction>();
      map.Add(SimpletronOpCodes.Read,         new ReadInstruction());
      map.Add(SimpletronOpCodes.Write,        new WriteInstruction());
      map.Add(SimpletronOpCodes.Load,         new LoadInstruction());
      map.Add(SimpletronOpCodes.Store,        new StoreInstruction());
      map.Add(SimpletronOpCodes.Add,          new AddInstruction());
      map.Add(SimpletronOpCodes.Subtract,     new SubtractInstruction());
      map.Add(SimpletronOpCodes.Divide,       new DivideInstruction());
      map.Add(SimpletronOpCodes.Multiply,     new MultiplyInstruction());
      map.Add(SimpletronOpCodes.Branch,       new BranchInstruction());
      map.Add(SimpletronOpCodes.BranchNeg,    new BranchNegInstruction());
      map.Add(SimpletronOpCodes.BranchZero,   new BranchZeroInstruction());
      map.Add(SimpletronOpCodes.Halt,         new HaltInstruction());
    }

    private static Instruction Create(SimpletronOpCodes opcode)
    {
      if (map.ContainsKey(opcode)) return map[opcode];

      //TODO Change ApplicationException to some Simpletron exception type.
      throw new ApplicationException(string.Format("Unknown InstructionType \"{0}\""));
    }

    public static ReadInstruction ReadInstruction()
    {
      return (ReadInstruction)Create(SimpletronOpCodes.Read);
    }

    public static WriteInstruction WriteInstruction()
    {
      return (WriteInstruction)Create(SimpletronOpCodes.Write);
    }

    public static LoadInstruction LoadInstruction()
    {
      return (LoadInstruction)Create(SimpletronOpCodes.Load);
    }

    public static StoreInstruction StoreInstruction()
    {
      return (StoreInstruction)Create(SimpletronOpCodes.Store);
    }

    public static AddInstruction AddInstruction()
    {
      return (AddInstruction)Create(SimpletronOpCodes.Add);
    }

    public static SubtractInstruction SubtractInstruction()
    {
      return (SubtractInstruction)Create(SimpletronOpCodes.Subtract);
    }

    public static DivideInstruction DivideInstruction()
    {
      return (DivideInstruction)Create(SimpletronOpCodes.Divide);
    }

    public static MultiplyInstruction MultiplyInstruction()
    {
      return (MultiplyInstruction)Create(SimpletronOpCodes.Multiply);
    }

    public static BranchInstruction BranchInstruction()
    {
      return (BranchInstruction)Create(SimpletronOpCodes.Branch);
    }

    public static BranchNegInstruction BranchNegInstruction()
    {
      return (BranchNegInstruction)Create(SimpletronOpCodes.BranchNeg);
    }

    public static BranchZeroInstruction BranchZeroInstruction()
    {
      return (BranchZeroInstruction)Create(SimpletronOpCodes.BranchZero);
    }

    public static HaltInstruction HaltInstruction()
    {
      return (HaltInstruction)Create(SimpletronOpCodes.Halt);
    }
  }
}
